package com.java.reflect;



import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.SecureClassLoader;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;

/**
 * @program: java_basic_knowledge
 * @description:
 * @author: CaoYong
 * @create: 2021-04-07 08:58
 **/
public class ClassKnowledge {


    public static void howToGetClass() {

        // 所有类的根父类Object都有一个getClass()方法可以获取对象的Class对象
        //Class是一个泛型类，getClass并不能知道具体的类型所以返回的是Class<?>
        Object object = new Object();
        Class<?> aClass = object.getClass();

        // 除了通过实例对象的getClass()方法为也可以通过类名.class获取Class对象
        Class<Date> dateClass = Date.class;

        // 也可以通过接口名获取Class对象
        Class<Comparable> comparableClass = Comparable.class;

        // 基本类型没有getClass()方法，但是也有Class对象，返回的类型参数是其包装类型
        Class<Integer> integerClass = int.class;

        // void作为特殊的返回类型也有其对应的Class
        Class<Void> voidClass = void.class;

        // 数组有对应数组类型的Class对象
        String[] array = new String[10];
        Class<? extends String[]> aClass1 = array.getClass();

        // 枚举类型也有对应的Class

        // Class有一个静态方法可以通过类名直接加载Class，获取Class对象
        try {
            Class<?> aClass2 = Class.forName("java.util.HashMap");
            System.out.println(aClass2.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**
     * 根据Class对象可以获取许多关于该类的信息，比如名称信息，字段信息，方法信息，创建对象和构造参数等
     */
    public static void howToUseClass() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, ClassNotFoundException {

        // 1. 获取名称信息
        Class<HashMap> hashMapClass = HashMap.class;
        System.out.println(hashMapClass.getName());
        System.out.println(hashMapClass.getSimpleName()); //不带包名
        System.out.println(hashMapClass.getCanonicalName());
        System.out.println(hashMapClass.getPackage());
        System.out.println("----------------------------------");


        // 2. 获取字段信息 Field
        Field[] fields = hashMapClass.getFields(); // 返回所有的publi字段，包括父类的，没有字段返回空数组
        Field[] declaredFields = hashMapClass.getDeclaredFields(); // 返回本类声明的所有字段包括非public的，不包括父类
//        Field maximum_capacity = hashMapClass.getField("MAXIMUM_CAPACITY");
        Field maximum_capacity2 = hashMapClass.getDeclaredField("MAXIMUM_CAPACITY"); // 根据字段名获取


        Arrays.stream(fields).forEach(System.out::println);
        System.out.println("--------------------------------");
        Arrays.stream(declaredFields).forEach(System.out::println);
        System.out.println("--------------------------------");
//        System.out.println(maximum_capacity);
        System.out.println("--------------------------------");
        System.out.println(maximum_capacity2);

        // Field可以获取字段的的相关信息，比如字段名，访问权限已经字段的值等
        System.out.println(maximum_capacity2.getName()); // 获取字段名
        System.out.println(maximum_capacity2.isAccessible()); // 获取访问权限
        maximum_capacity2.setAccessible(true); // 设置访问权限
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        Object object = maximum_capacity2.get(objectObjectHashMap); // 获取指定对象的字段的值
        System.out.println("object:" + object);
//        maximum_capacity2.set(objectObjectHashMap, 20); // 设置指定对象的字段的值
//        Object object2 = maximum_capacity2.get(objectObjectHashMap);
//        System.out.println("object2:" + object2);
        int modifiers = maximum_capacity2.getModifiers();
        System.out.println(modifiers);
        System.out.println("-------------------------------------");

        // 3. 获取方法信息 Method
        Method[] methods = hashMapClass.getMethods();
        Arrays.stream(methods).forEach(System.out::println);
        System.out.println("-------------------------------------"); // 获取所有的public方法，包括父类的
        Method[] declaredMethods = hashMapClass.getDeclaredMethods(); // 获取本类的所有方法，包括非public
        Arrays.stream(declaredMethods).forEach(System.out::println);
        Method isEmpty = hashMapClass.getMethod("isEmpty"); // 获取指定的方法
        System.out.println("-------------------------------------");
        System.out.println(isEmpty.getName());
        Object invoke = isEmpty.invoke(objectObjectHashMap); // 执行具体实例的相应方法
        System.out.println(invoke);
        System.out.println("----------------------------------");

        // 4. 创建对象和构造方法
        HashMap<String, Integer> hashMap = hashMapClass.newInstance(); // 调用类的默认构造方法
        hashMap.put("hello", 123);
        System.out.println(hashMap.get("hello"));
        Constructor<?>[] constructors = hashMapClass.getConstructors();
        Constructor<?>[] declaredConstructors = hashMapClass.getDeclaredConstructors();
        Constructor<HashMap> constructor = hashMapClass.getConstructor();
        HashMap hashMap1 = constructor.newInstance();
        System.out.println("-----------------------------------");

        // 5. 类型检查和转换
        System.out.println(objectObjectHashMap instanceof HashMap); // instanceof关键字判断变量指向的实际对象类型
        System.out.println(hashMapClass.isInstance(objectObjectHashMap)); // Class类的getInstance()方法可以动态判断类型
        System.out.println("-----------------------------------");

        // 6. Class的类型信息
        System.out.println(hashMapClass.isArray()); // 是否是数组
        System.out.println(hashMapClass.isPrimitive()); // 是否是基本类型
        System.out.println(hashMapClass.isInterface()); // 是否是接口
        System.out.println(hashMapClass.isAnnotation()); // 是否是注解
        System.out.println(hashMapClass.isAnonymousClass()); // 是否是匿名内部类
        System.out.println(hashMapClass.isMemberClass()); //是否是成员类
        System.out.println(hashMapClass.isLocalClass()); // 是否是本地类
        System.out.println("------------------------------------");

        // 7. 获取类声明的信息
        System.out.println(hashMapClass.getSuperclass().getName()); // 获取父类
        Class<?>[] interfaces = hashMapClass.getInterfaces(); // 获取接口
        Arrays.stream(interfaces).forEach(inter -> {
            System.out.println(inter.getName());
        });
        Annotation[] declaredAnnotations = hashMapClass.getDeclaredAnnotations(); // 获取注解
        Arrays.stream(declaredAnnotations).forEach(annotation -> {
            System.out.println(annotation.toString());
        });
        System.out.println("------------------------------------");

        // 8.类的加载
        Class<?> aClass = Class.forName(hashMapClass.getName()); //Class类根据类名加载类
        System.out.println(aClass.getName());
        Class<?> aClass1 = Class.forName(hashMapClass.getName(), false, ClassLoader.getSystemClassLoader()); // 指定是否进行初始化及类加载器
        System.out.println(aClass1.getName());

        // 9. 数组的反射
        String[] arr = new String[10];
        arr[0] = "张三";
        System.out.println(arr.getClass().getComponentType());



    }

    public static void main(String[] args) throws Exception{
        howToUseClass();
    }


}
